package io.wanghaoran.project.module.system.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.tmt.v20180321.TmtClient;
import com.tencentcloudapi.tmt.v20180321.models.TextTranslateRequest;
import com.tencentcloudapi.tmt.v20180321.models.TextTranslateResponse;

import io.wanghaoran.project.framework.security.util.SecurityUtils;
import io.wanghaoran.project.module.system.entity.UserTokens;
import io.wanghaoran.project.module.system.entity.UserTokensLog;
import io.wanghaoran.project.module.system.model.dto.FluxRequestDTO;
import io.wanghaoran.project.module.system.model.dto.FluxResponseDTO;
import io.wanghaoran.project.module.system.service.UserTokensService;
import io.wanghaoran.project.module.system.service.UserTokensLogService;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Api(tags = "改图模块")
@Controller
@RequestMapping("/system/ImageEdit")
@RequiredArgsConstructor
public class SysImageController {
    private static final String SUFFIX = "system/ImageEdit";
    private static final String UPLOAD_DIR = "src/main/resources/static/upload/";
    private static final Logger logger = LoggerFactory.getLogger(SysImageController.class);

    @Value("${image.edit.tokens.api:}")
    private String fluxApiUrl;
    
    @Value("${image.edit.tokens.key:}")
    private String fluxApiKey;

    @Value("${image.edit.tokens.blend-api:}")
    private String fluxBlendApiUrl;

    private final RestTemplate restTemplate = new RestTemplate();

    private final UserTokensService userTokensService;
    private final UserTokensLogService userTokensLogService;

    @Value("${image.edit.tokens.single-deduct:1}")
    private int singleDeductTokens;

    @Value("${image.edit.tokens.blend-deduct:2}")
    private int blendDeductTokens;

    @Value("${tencent.cloud.secretId:}")
    private String secretId;

    @Value("${tencent.cloud.secretKey:}")
    private String secretKey;

    @GetMapping("index")
    public String index() {
        String username = SecurityUtils.getUserName();
        if ("admin".equals(username)) {
            return SUFFIX + "/index";
        }
        QueryWrapper<UserTokens> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name", username);
        UserTokens userTokens = userTokensService.getOne(queryWrapper);
        
        if (userTokens == null || userTokens.getTokensCount() == null || userTokens.getTokensCount() <= 0) {
            return "redirect:/system/ImageEdit/tokenError";
        }
        return SUFFIX + "/index";
    }

    @GetMapping("tokenError")
    public String tokenError() {
        return SUFFIX + "/tokenError";
    }

    @PostMapping("upload")
    @ResponseBody
    public Map<String, Object> upload(@RequestParam("file") MultipartFile file) {
        Map<String, Object> result = new HashMap<>();
        
        if (file.isEmpty()) {
            result.put("success", false);
            result.put("message", "文件为空");
            return result;
        }

        try {
            String projectRoot = System.getProperty("user.dir");
            String uploadPath = Paths.get(projectRoot, UPLOAD_DIR).toString();
            
            File uploadDir = new File(uploadPath);
            if (!uploadDir.exists()) {
                uploadDir.mkdirs();
            }

            String originalFilename = file.getOriginalFilename();
            String fileExtension = "";
            if (originalFilename != null && originalFilename.contains(".")) {
                fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            }
            String uniqueFilename = UUID.randomUUID().toString() + fileExtension;

            File destFile = new File(uploadPath, uniqueFilename);
            file.transferTo(destFile);

            result.put("success", true);
            result.put("message", "文件上传成功");
            result.put("filename", uniqueFilename);
        } catch (IOException e) {
            result.put("success", false);
            result.put("message", "文件上传失败: " + e.getMessage());
        }

        return result;
    }

    @PostMapping("/process-single")
    @ResponseBody
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> processSingleImage(@RequestParam("image") MultipartFile image,
            @RequestParam("prompt") String prompt,
            @RequestParam(value = "cfgScale", required = false) Double cfgScale,
            @RequestParam(value = "aspectWidth", required = false) Integer aspectWidth,
            @RequestParam(value = "aspectHeight", required = false) Integer aspectHeight) {
        
        Map<String, Object> result = new HashMap<>();
    
        String username = SecurityUtils.getUserName();
        QueryWrapper<UserTokens> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name", username);
        UserTokens userTokens = userTokensService.getOne(queryWrapper);
    
        if (!username.equals("admin") && (userTokens == null || userTokens.getTokensCount() < singleDeductTokens)) {
            result.put("success", false);
            result.put("message", "Token不足，请充值");
            return result;
        }
    
        try {
            // 直接从MultipartFile读取图片数据并转换为base64
            byte[] imageBytes = image.getBytes();
            String base64Image = java.util.Base64.getEncoder().encodeToString(imageBytes);
            
            String aspectRatio = (aspectWidth != null && aspectHeight != null) ? aspectWidth + ":" + aspectHeight : null;
            String processedImageUrl = processImageWithFluxApi(base64Image, prompt, true, aspectRatio);
            
            String proxyImageUrl = "/system/ImageEdit/proxy-image?url=" + 
                java.net.URLEncoder.encode(processedImageUrl, "UTF-8");
    
            if (!username.equals("admin")) {
                userTokens.setTokensCount(userTokens.getTokensCount() - singleDeductTokens);
                boolean updateSuccess = userTokensService.updateById(userTokens);
    
                if (!updateSuccess) {
                    throw new RuntimeException("扣除Token失败");
                }
    
                UserTokensLog log = new UserTokensLog();
                log.setUserName(username);
                log.setCallMethod("单图模式");
                log.setDeductTokens((long) singleDeductTokens);
                boolean saveSuccess = userTokensLogService.save(log);
                result.put("remainingTokens", userTokens.getTokensCount());
                if (!saveSuccess) {
                    throw new RuntimeException("记录操作日志失败");
                }
            }
            result.put("success", true);
            result.put("message", "图片处理完成");
            result.put("processedImageUrl", proxyImageUrl);
            
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "处理失败: " + e.getMessage());
            logger.error("图片处理失败", e);
            throw new RuntimeException(e);
        }
        return result;
    }

    @GetMapping("/proxy-image")
    public void proxyImage(@RequestParam("url") String imageUrl, HttpServletResponse response) {
        try {
            URL url = new URL(imageUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(50000);
            connection.setReadTimeout(150000);
            
            String contentType = connection.getContentType();
            if (contentType == null) {
                contentType = "image/jpeg";
            }
            
            response.setContentType(contentType);
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
            response.setHeader("Access-Control-Allow-Headers", "*");
            response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Expires", "0");
            
            try (InputStream inputStream = connection.getInputStream();
                 OutputStream outputStream = response.getOutputStream()) {
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
        } catch (Exception e) {
            logger.error("代理图片加载失败: {}", imageUrl, e);
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
        }
    }

    @GetMapping("text-translate-en")
    @ResponseBody
    public CompletableFuture<Map<String, Object>> textTranslateEn(
            @RequestParam(value = "text", required = false) String text) {
        return CompletableFuture.supplyAsync(() -> {
            Map<String, Object> result = new HashMap<>();

            if (text == null || text.trim().isEmpty()) {
                result.put("success", 500);
                result.put("message", "请输入文字");
                return result;
            }

            try {
                String translatedText = translateToEnglish(text);
                result.put("success", 200);
                result.put("translated_text", translatedText);
                result.put("message", "成功");
            } catch (Exception e) {
                result.put("success", 500);
                result.put("message", "翻译失败: " + e.getMessage());
            }
            return result;
        });
    }

    @Async
    protected String translateToEnglish(String text) throws TencentCloudSDKException {
        try {
            Credential cred = new Credential(secretId, secretKey);

            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setEndpoint("tmt.tencentcloudapi.com");

            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);

            TmtClient client = new TmtClient(cred, "ap-beijing", clientProfile);

            TextTranslateRequest req = new TextTranslateRequest();
            req.setSourceText(text);
            req.setSource("zh");
            req.setTarget("en");
            req.setProjectId(0L);

            TextTranslateResponse resp = client.TextTranslate(req);
            return resp.getTargetText();
        } catch (TencentCloudSDKException e) {
            throw new RuntimeException("腾讯翻译API调用失败: " + e.getMessage(), e);
        }
    }

    @PostMapping("/process-blend")
    @ResponseBody
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> processBlendImages(@RequestParam("baseImage") MultipartFile baseImage,
            @RequestParam("blendImage") MultipartFile blendImage,
            @RequestParam("prompt") String prompt,
            @RequestParam(value = "cfgScale", required = false) Double cfgScale,
            @RequestParam(value = "aspectWidth", required = false) Integer aspectWidth,
            @RequestParam(value = "aspectHeight", required = false) Integer aspectHeight) {
        
        Map<String, Object> result = new HashMap<>();
    
        String username = SecurityUtils.getUserName();
        QueryWrapper<UserTokens> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name", username);
        UserTokens userTokens = userTokensService.getOne(queryWrapper);
    
        if (!username.equals("admin") && (userTokens == null || userTokens.getTokensCount() < blendDeductTokens)) {
            result.put("success", false);
            result.put("message", "Token不足，请充值");
            return result;
        }
    
        try {
            // 直接从MultipartFile读取图片数据并转换为base64
            byte[] imageBytes1 = baseImage.getBytes();
            String base64Image1 = java.util.Base64.getEncoder().encodeToString(imageBytes1);
    
            byte[] imageBytes2 = blendImage.getBytes();
            String base64Image2 = java.util.Base64.getEncoder().encodeToString(imageBytes2);
    
            String aspectRatio = (aspectWidth != null && aspectHeight != null) ? aspectWidth + ":" + aspectHeight : null;
            String processedImageUrl = processImageWithFluxApiBlend(base64Image1, base64Image2, prompt, aspectRatio);
            
            String proxyImageUrl = "/system/ImageEdit/proxy-image?url=" + 
                java.net.URLEncoder.encode(processedImageUrl, "UTF-8");
    
            // 扣除Token
            if (!username.equals("admin")) {
                userTokens.setTokensCount(userTokens.getTokensCount() - blendDeductTokens);
                boolean updateSuccess = userTokensService.updateById(userTokens);
    
                if (!updateSuccess) {
                    throw new RuntimeException("扣除Token失败");
                }
    
                UserTokensLog log = new UserTokensLog();
                log.setUserName(username);
                log.setCallMethod("融合模式");
                log.setDeductTokens((long) blendDeductTokens);
                boolean saveSuccess = userTokensLogService.save(log);
    
                result.put("remainingTokens", userTokens.getTokensCount());
                if (!saveSuccess) {
                    throw new RuntimeException("记录操作日志失败");
                }
            }
            result.put("success", true);
            result.put("message", "图片融合完成");
            result.put("processedImageUrl", proxyImageUrl);
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "处理失败: " + e.getMessage());
            logger.error("图片融合失败", e);
            throw new RuntimeException(e);
        }
        return result;
    }

    /**
     * 调用Flux API进行图片融合
     */
    private String processImageWithFluxApiBlend(String baseImageData, String blendImageData, String prompt, String aspectRatio) throws Exception {
        FluxRequestDTO request = new FluxRequestDTO(prompt, baseImageData, blendImageData);
        request.setOutputFormat("png");
        if (aspectRatio != null) {
            request.setAspectRatio(aspectRatio);
        }
        
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("x-key", fluxApiKey);
    
        HttpEntity<FluxRequestDTO> entity = new HttpEntity<>(request, headers);
    
        ResponseEntity<FluxResponseDTO> response = restTemplate.postForEntity(
                fluxBlendApiUrl, entity, FluxResponseDTO.class);
    
        if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) {
            throw new RuntimeException("Flux API调用失败");
        }
    
        FluxResponseDTO fluxResponse = response.getBody();
        String taskId = fluxResponse.getId();
        String pollingUrl = fluxResponse.getPollingUrl();
    
        if (taskId == null || pollingUrl == null) {
            throw new RuntimeException("无效的Flux API响应");
        }
    
        return pollFluxResult(pollingUrl);
    }

    @PostMapping("/process-flux-simple")
    @ResponseBody
    public Map<String, Object> processImageWithFluxSimple(@RequestParam("imageUrl") String imageUrl,
            @RequestParam("prompt") String prompt) {
        Map<String, Object> result = new HashMap<>();

        try {
            String processedImageUrl = processImageWithFluxApi2(imageUrl, prompt);
            String proxyImageUrl = "/system/ImageEdit/proxy-image?url=" + 
                java.net.URLEncoder.encode(processedImageUrl, "UTF-8");
            result.put("success", true);
            result.put("processedImageUrl", proxyImageUrl);
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "处理失败: " + e.getMessage());
            logger.error("Flux处理失败", e);

        }

        return result;
    }



    /**
     * 核心方法：调用Flux API处理图片
     * @param imageData 图片数据（可以是URL或base64字符串）
     * @param prompt 提示词
     * @param isBase64 是否为base64格式
     * @param aspectRatio 宽高比字符串，格式为 "width:height"，为null时不传递
     */
    private String processImageWithFluxApi(String imageData, String prompt, boolean isBase64, String aspectRatio) throws Exception {
        FluxRequestDTO request = new FluxRequestDTO(prompt, imageData);
        if (aspectRatio != null) {
            request.setAspectRatio(aspectRatio);
        }
        
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("x-key", fluxApiKey);
    
        HttpEntity<FluxRequestDTO> entity = new HttpEntity<>(request, headers);
    
        ResponseEntity<FluxResponseDTO> response = restTemplate.postForEntity(
                fluxApiUrl, entity, FluxResponseDTO.class);
    
        if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) {
            throw new RuntimeException("Flux API调用失败");
        }
    
        FluxResponseDTO fluxResponse = response.getBody();
        String taskId = fluxResponse.getId();
        String pollingUrl = fluxResponse.getPollingUrl();
    
        if (taskId == null || pollingUrl == null) {
            throw new RuntimeException("无效的Flux API响应");
        }
    
        return pollFluxResult(pollingUrl);
    }

    private String processImageWithFluxApi2(String imageUrl, String prompt) throws Exception {
        FluxRequestDTO request = new FluxRequestDTO(prompt, imageUrl);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("x-key", fluxApiKey);

        HttpEntity<FluxRequestDTO> entity = new HttpEntity<>(request, headers);

        ResponseEntity<FluxResponseDTO> response = restTemplate.postForEntity(
                fluxApiUrl, entity, FluxResponseDTO.class);

        if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) {
            throw new RuntimeException("Flux API调用失败");
        }

        FluxResponseDTO fluxResponse = response.getBody();
        String taskId = fluxResponse.getId();
        String pollingUrl = fluxResponse.getPollingUrl();

        if (taskId == null || pollingUrl == null) {
            throw new RuntimeException("无效的Flux API响应");
        }

        return pollFluxResult(pollingUrl);
    }

    private String pollFluxResult(String pollingUrl) throws Exception {
        int maxRetries = 60;
        int retryInterval = 5;

        for (int attempt = 0; attempt < maxRetries; attempt++) {
            ResponseEntity<FluxResponseDTO> response = restTemplate.getForEntity(
                    pollingUrl, FluxResponseDTO.class);

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                FluxResponseDTO fluxResponse = response.getBody();
                String status = fluxResponse.getStatus();

                if ("Ready".equals(status)) {
                    if (fluxResponse.getResult() != null &&
                            fluxResponse.getResult().getSample() != null) {
                        return fluxResponse.getResult().getSample();
                    }
                    throw new RuntimeException("未获取到处理后的图片URL");
                } else if ("failed".equals(status)) {
                    throw new RuntimeException("Flux处理任务失败");
                }
            }

            Thread.sleep(retryInterval * 1000);
        }

        throw new RuntimeException("处理超时，请稍后重试");
    }
}
